package com.yiren.dbaa.module.practice_set.map.model;

import android.content.Context;

import com.yiren.backstage.config.api.LoadConfigApi;
import com.yiren.backstage.config.bean.device.StationParamConfigBean;
import com.yiren.backstage.config.bean.device.UserParamConfigBean;
import com.yiren.backstage.currency.bean.GpsInfoBean;
import com.yiren.backstage.currency.bean.PointBean;
import com.yiren.backstage.currency.entity.TrajectoryEntity;
import com.yiren.backstage.currency.entity.TrajectoryPointEntity;
import com.yiren.backstage.currency.utils.GpsUtil;
import com.yiren.backstage.db.dao.controller.TrajectDbController;
import com.yiren.dbaa.currency.model.MultiLaneModel;
import com.yiren.dbaa.module.practice_set.map.contract.CollectContract;

import org.apache.commons.lang.StringUtils;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.UUID;

/**
 * @author lwb
 * @date : 2022/6/7 14:03
 * @description: 采集modle实现
 */
public class CollectModel implements CollectContract.Model {

    private Context context;
    private boolean isBaseCalibration;
    private UserParamConfigBean userParamConfig;
    private StationParamConfigBean stationParamConfig;

    public CollectModel(Context context) {
        this.context = context;
        userParamConfig = LoadConfigApi.loadUserParamConfig(context);
        stationParamConfig = LoadConfigApi.loadStationParamConfig(context);
        isBaseCalibration = loadPointCalibrationStatus(stationParamConfig.isBaseCalibration());
    }

    @Override
    public PointBean setTrajectoryPoint(GpsInfoBean gpsInfo) {
        PointBean point = new PointBean();
        point.setLon(gpsInfo.getLongitude());
        point.setLat(gpsInfo.getLatitude());
        point.setHigh(gpsInfo.getAltitude());
        if (isBaseCalibration && stationParamConfig.isBaseCalibration()) {
            String locations[] = stationParamConfig.getBaseStationLocation().split(",");
            point.setX(GpsUtil.getDistanceX(Double.parseDouble(locations[0]), Double.parseDouble(locations[1]), gpsInfo.getLongitude()));
            point.setY(GpsUtil.getDistanceY(Double.parseDouble(locations[1]), gpsInfo.getLatitude()));
            point.setZ(GpsUtil.getDistanceZ(Double.parseDouble(locations[2]), gpsInfo.getAltitude()));
        } else {
            point.setX(gpsInfo.getDistanceX());
            point.setY(gpsInfo.getDistanceY());
            point.setZ(gpsInfo.getDistanceZ());
        }
        return point;
    }

    @Override
    public MultiLaneModel setMultiLaneModel() {
        MultiLaneModel multiLaneModel = new MultiLaneModel();
        multiLaneModel.setShowNumber(false);
        multiLaneModel.setLineType(1);
        multiLaneModel.setLineColor(1);
        multiLaneModel.setLineWidth(15);
        multiLaneModel.setAdd(true);
        multiLaneModel.setDelete(true);
        multiLaneModel.setTrajectoryPoints(new ArrayList<TrajectoryPointEntity>());
        multiLaneModel.setCollectEnd(false);
        return multiLaneModel;
    }

    @Override
    public void saveSHXLeftPoint(List<TrajectoryPointEntity> trajectoryPoints, float pyDistance) {
        if (null != trajectoryPoints && trajectoryPoints.size() > 1) {
            TrajectoryEntity trajectory = trajectoryPoints.get(0).getTrajectory();
            for (int i = 0; i < trajectoryPoints.size(); i++) {
                if (i < trajectoryPoints.size() - 1) {
                    PointBean onePoint = trajectoryPoints.get(i).getPoint();
                    PointBean twoPoint = trajectoryPoints.get(i + 1).getPoint();
                    if (i == 0) {
                        //求第一点
                        PointBean threePoint = jtThreePoint(twoPoint, onePoint, 0, -pyDistance);
                        saveSHXLeftPoint(threePoint, trajectory, "2" + (trajectoryPoints.size() * 2));

                        //求第二点
                        threePoint = jtThreePoint(onePoint, twoPoint, 0, pyDistance);
                        saveSHXLeftPoint(threePoint, trajectory, "2" + (trajectoryPoints.size() * 2 - 1));
                    } else {
                        PointBean threePoint = jtThreePoint(onePoint, twoPoint, 0, pyDistance);
                        saveSHXLeftPoint(threePoint, trajectory, "2" + (trajectoryPoints.size() * 2 - i - 1));
                    }
                }
            }
        }
    }

    @Override
    public boolean saveTrajectoryPoint(TrajectoryPointEntity trajectoryPoint, int operCode) {
        trajectoryPoint.setH(trajectoryPoint.getPoint().getHigh());
        trajectoryPoint.setLat(trajectoryPoint.getPoint().getLat());
        trajectoryPoint.setLon(trajectoryPoint.getPoint().getLon());
        trajectoryPoint.setX(trajectoryPoint.getPoint().getX());
        trajectoryPoint.setY(trajectoryPoint.getPoint().getY());
        trajectoryPoint.setZ(trajectoryPoint.getPoint().getZ());
        trajectoryPoint.setId(UUID.randomUUID().toString());
        trajectoryPoint.setCreateUser(String.valueOf(userParamConfig.getUserInfo().getId()));
        trajectoryPoint.setStatus(stationParamConfig.isBaseCalibration() ? "CALIBRATION" : "NOT_CALIBRATION");
        if (operCode == 1) {
            return TrajectDbController.getInstance(false).insert(trajectoryPoint);
        } else {
            return TrajectDbController.getInstance(false).update(trajectoryPoint);
        }
    }

    /**
     * 生成双簧线左侧的点位
     *
     * @param threePoint
     * @param trajectory
     * @param orderIndex
     */
    private void saveSHXLeftPoint(PointBean threePoint, TrajectoryEntity trajectory, String orderIndex) {
        TrajectoryPointEntity trajectoryPoint = new TrajectoryPointEntity();
        trajectoryPoint.setPoint(threePoint);
        trajectoryPoint.setTrajectory(trajectory);
        trajectoryPoint.setTrajectoryId(trajectory.getId());
        trajectoryPoint.setOrderIndex(orderIndex);
        saveTrajectoryPoint(trajectoryPoint, 1);
    }

    private PointBean jtThreePoint(PointBean onePoint, PointBean twoPoint, double height, double width) {
        PointBean point = new PointBean();
        double awrad = Math.atan(width / height);
        double arrowSize = Math.sqrt(width * width + height * height);
        double[] arrXY = rotateVec(twoPoint.getX() - onePoint.getX(), twoPoint.getY() - onePoint.getY(), awrad, arrowSize);
        float x = (float) (twoPoint.getX() - arrXY[0]);
        float y = (float) (twoPoint.getY() - arrXY[1]);
        point.setX(x);
        point.setY(y);
        point.setZ(twoPoint.getZ());
        if (stationParamConfig.isBaseCalibration() && StringUtils.isNotEmpty(stationParamConfig.getBaseStationLocation())) {
            point.setLon(twoPoint.getLon() + GpsUtil.getDistanceLon(x - twoPoint.getX(), twoPoint.getLat()));
            point.setLat(twoPoint.getLat() + GpsUtil.getDistanceLat(y - twoPoint.getY()));
            point.setHigh(twoPoint.getHigh());
        }
        return point;
    }

    public double[] rotateVec(float px, float py, double ang, double newLen) {
        double mathstr[] = new double[2];
        double vx = px * Math.cos(ang) - py * Math.sin(ang);
        double vy = px * Math.sin(ang) + py * Math.cos(ang);
        double d = Math.sqrt(vx * vx + vy * vy);
        vx = vx / d * newLen;
        vy = vy / d * newLen;
        mathstr[0] = vx;
        mathstr[1] = vy;
        return mathstr;
    }

    @Override
    public boolean loadPointCalibrationStatus(Boolean isBaseCalibration) {
        List<TrajectoryPointEntity> trajectoryList = TrajectDbController.getInstance(false).queryByNativeSql(TrajectoryPointEntity.class,
                "WHERE (SYN_STATE != '3' OR SYN_STATE is NULL)", null);
        if (trajectoryList.size() == 0 && isBaseCalibration) {
            return true;
        }
        for (TrajectoryPointEntity trajectoryPoint : trajectoryList) {
            String status = trajectoryPoint.getStatus();
            if (StringUtils.isNotEmpty(status)) {
                if (status.equals("NOT_CALIBRATION")) {
                    return false;
                }
            } else {
                return false;
            }
        }
        return true;
    }

    @Override
    public HashMap<String, List<TrajectoryPointEntity>> loadNearbyPoint(float minX, float maxX, float minY, float maxY) {
        StringBuilder cond = new StringBuilder();
        cond.append(" AND CAST(x as int) >" + minX + " AND CAST(x as int) <" + maxX + " AND CAST(y as int) >" + minY + " AND CAST(y as int) <" + maxY);
        String sql = "WHERE SYN_STATE != '3' OR SYN_STATE is NULL" + cond.toString() + " ORDER BY CAST(ORDER_INDEX as int)";
        List<TrajectoryPointEntity> tpList = TrajectDbController.getInstance(false).queryByNativeSql(TrajectoryPointEntity.class, sql, null);
        HashMap<String, List<TrajectoryPointEntity>> map = new HashMap<String, List<TrajectoryPointEntity>>();
        for (int i = 0; i < tpList.size(); i++) {
            TrajectoryPointEntity tp = tpList.get(i);
            String trajectoryId = tp.getTrajectoryId();
            TrajectoryEntity trajectoryEntity = (TrajectoryEntity) TrajectDbController.getInstance(false).queryById(trajectoryId, TrajectoryEntity.class);
            if (null == trajectoryEntity) continue;
            tp.setTrajectory(trajectoryEntity);
            PointBean point = new PointBean();
            point.setX(tp.getX());
            point.setY(tp.getY());
            point.setZ(tp.getZ());
            point.setLon(tp.getLon());
            point.setLat(tp.getLat());
            point.setHigh(tp.getH());
            tp.setPoint(point);
            if (null == map.get(trajectoryId)) {
                List<TrajectoryPointEntity> trajectoryPoints = new ArrayList<>();
                trajectoryPoints.add(tpList.get(i));
                map.put(trajectoryId, trajectoryPoints);
            } else {
                map.get(trajectoryId).add(tpList.get(i));
            }
        }
        return map;
    }

    @Override
    public HashMap<String, List<TrajectoryPointEntity>> loadNearbyPoint(double minLon, double maxLon, double minLat, double maxLat, boolean flag) {
        String locations[] = stationParamConfig.getBaseStationLocation().split(",");
        StringBuilder cond = new StringBuilder();
        cond.append(" AND LON >" + minLon + " AND LON <" + maxLon + " AND LAT >" + minLat + " AND LAT <" + maxLat);
        String sql = "WHERE SYN_STATE != '3' OR SYN_STATE is NULL" + cond.toString() + " ORDER BY CAST(ORDER_INDEX as int)";
        List<TrajectoryPointEntity> tpList = TrajectDbController.getInstance(false).queryByNativeSql(TrajectoryPointEntity.class, sql, null);
        HashMap<String, List<TrajectoryPointEntity>> map = new HashMap<String, List<TrajectoryPointEntity>>();
        for (int i = 0; i < tpList.size(); i++) {
            TrajectoryPointEntity tp = tpList.get(i);
            String trajectoryId = tp.getTrajectoryId();
            TrajectoryEntity trajectoryEntity = (TrajectoryEntity) TrajectDbController.getInstance(false).queryById(trajectoryId, TrajectoryEntity.class);
            if (null == trajectoryEntity) continue;
            tp.setTrajectory(trajectoryEntity);
            PointBean point = new PointBean();
            double lon = tpList.get(i).getLon();
            double lat = tpList.get(i).getLat();
            double high = tpList.get(i).getH();
            point.setX(GpsUtil.getDistanceX(Double.parseDouble(locations[0]), Double.parseDouble(locations[1]), lon));
            point.setY(GpsUtil.getDistanceY(Double.parseDouble(locations[1]), lat));
            point.setZ(GpsUtil.getDistanceZ(Double.parseDouble(locations[2]), high));
            point.setLon(lon);
            point.setLat(lat);
            point.setHigh(high);
            tp.setPoint(point);
            if (null == map.get(trajectoryId)) {
                List<TrajectoryPointEntity> trajectoryPoints = new ArrayList<>();
                trajectoryPoints.add(tp);
                map.put(trajectoryId, trajectoryPoints);
            } else {
                map.get(trajectoryId).add(tp);
            }
        }
        return map;
    }

    @Override
    public TrajectoryPointEntity loadMinPoint(float x, boolean isDy) {
        TrajectoryPointEntity trajectoryPoint = null;
        String sql = "";
        if (isDy) {
            sql = "WHERE (x>" + x + ")" + " order by x asc LIMIT 1";
        } else {
            sql = "WHERE (x<" + x + ")" + " order by x asc LIMIT 1";
        }
        List<TrajectoryPointEntity> tpList = TrajectDbController.getInstance(false).queryByNativeSql(TrajectoryPointEntity.class, sql, null);
        if (tpList.size() > 0) {
            trajectoryPoint = new TrajectoryPointEntity();
            PointBean point = new PointBean();
            point.setX(tpList.get(0).getX());
            point.setY(tpList.get(0).getY());
            point.setZ(tpList.get(0).getZ());
            point.setLon(tpList.get(0).getLon());
            point.setLat(tpList.get(0).getLat());
            point.setHigh(tpList.get(0).getH());
            trajectoryPoint.setPoint(point);
            trajectoryPoint.setOrderIndex(tpList.get(0).getOrderIndex());
        }
        return trajectoryPoint;
    }

    @Override
    public TrajectoryPointEntity loadMinPoint(double longitude, boolean isDy, boolean flag) {
        TrajectoryPointEntity trajectoryPoint = null;
        String locations[] = stationParamConfig.getBaseStationLocation().split(",");
        String sql = "";
        if (isDy) {
            sql = "WHERE (LON>" + longitude + ")" + " order by LON asc LIMIT 1";
        } else {
            sql = "WHERE (LON<" + longitude + ")" + " order by LON asc LIMIT 1";
        }
        List<TrajectoryPointEntity> tpList = TrajectDbController.getInstance(false).queryByNativeSql(TrajectoryPointEntity.class, sql, null);
        if (tpList.size() > 0) {
            TrajectoryPointEntity tp = tpList.get(0);
            trajectoryPoint = new TrajectoryPointEntity();
            PointBean point = new PointBean();
            double lon = tp.getLon();
            double lat = tp.getLat();
            double high = tp.getH();
            point.setX(GpsUtil.getDistanceX(Double.parseDouble(locations[0]), Double.parseDouble(locations[1]), lon));
            point.setY(GpsUtil.getDistanceY(Double.parseDouble(locations[1]), lat));
            point.setZ(GpsUtil.getDistanceZ(Double.parseDouble(locations[2]), high));
            point.setLon(lon);
            point.setLat(lat);
            point.setHigh(high);
            trajectoryPoint.setPoint(point);
            trajectoryPoint.setOrderIndex(tp.getOrderIndex());
        }
        return trajectoryPoint;
    }

}
